package com.lyl.security.module.login.service.impl;

import cn.hutool.core.util.IdUtil;
import com.lyl.security.common.result.Result;
import com.lyl.security.common.utils.RedisUtil;
import com.lyl.security.module.login.model.dto.UserDTO;
import com.lyl.security.module.login.service.LoginService;
import com.lyl.security.module.security.constant.Constants;
import com.lyl.security.module.security.model.LoginUser;
import com.lyl.security.module.security.properties.SecurityProperties;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author Mr.Luo
 * @date 2022-09-09 12:25
 * @desc
 */
@Service
@RequiredArgsConstructor
public class LoginServiceImpl implements LoginService {
    private final AuthenticationManager authenticationManager;
    private final SecurityProperties securityProperties;

    @Override
    public Result<Object> login(UserDTO dto) {
        Authentication authenticate;
        try {
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(dto.getUsername(), dto.getPassword());
            authenticate = authenticationManager.authenticate(authentication);
        } catch (AuthenticationException e) {
            if (e instanceof BadCredentialsException) {
                throw new RuntimeException("用户密码不匹配异常");
            } else {
                throw new RuntimeException("业务异常" + e.getMessage());
            }
        }
        LoginUser loginDetails = (LoginUser) authenticate.getPrincipal();
        return Result.ok(createToken(loginDetails));
    }

    public String createToken(LoginUser loginUser) {
        String token = IdUtil.fastUUID();
        loginUser.setToken(token);
        refreshToken(loginUser);

        Map<String, Object> claims = new HashMap<>();
        claims.put(Constants.LOGIN_USER_KEY, token);
        return createToken(claims);
    }

    /**
     * 刷新令牌有效期
     *
     * @param loginUser 登录信息
     */
    public void refreshToken(LoginUser loginUser) {
        loginUser.setLoginTime(System.currentTimeMillis());
        loginUser.setExpireTime(loginUser.getLoginTime() + securityProperties.getToken().getExpireTime() * Constants.MILLIS_MINUTE);
        // 根据uuid将loginUser缓存
        String userKey = Constants.LOGIN_TOKEN_KEY + loginUser.getToken();
        RedisUtil.set(userKey, loginUser, securityProperties.getToken().getExpireTime(), TimeUnit.MINUTES);
    }


    private String createToken(Map<String, Object> claims) {
        String token = Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS512, securityProperties.getToken().getSecret()).compact();
        return token;
    }
}
